#include "socket_base.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/un.h>
#include <fcntl.h>
//#include <netinet/tcp.h>//add for TCP_KEEP ALIVE SET
#include <netinet/in.h>//
#include <linux/socket.h>
#include <unistd.h>
//#include <linux/tcp.h>

#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif


#include "p_lib.h"
#include "common.h"
/*=================================================
SOCKET BASE FUNCTION PART
===================================================*/
/** 
 * Brief description:


 
    Connect to server by server ip address & server listening port. 
 * Detail description:
 * @param[in]
    char* sIpAddr: the server's ip address(string)
    int iPort(int) :the port server is listening
 * @param[out]  None
 * @retval  <0 fail 
 * @retval  >0 success and the value will be the socket_fd
 * @par sIpAddr:Type is string ,the ip address of server
 *     
 * @par iPort:Type is int,the port of server
 *     
 * @par 
 *    
 */  
int TCP_ConnectToServer(char* sIpAddr, int iPort)
{
	int iSockFd;
	struct sockaddr_in sai;
	
	if ((iSockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
	{
		return ERR_SOCKET;
	}
	
	sai.sin_family = AF_INET;
	sai.sin_port = htons(iPort);
	sai.sin_addr.s_addr = inet_addr(sIpAddr);
	bzero(&(sai.sin_zero), 8); 
	if (connect(iSockFd, (struct sockaddr *)&sai, sizeof(struct sockaddr)) < 0) 
	{
		close(iSockFd); //add by lk 20150514
		return ERR_CONNECT;
	}

	return iSockFd;
}

int TCP_ConnectToServerTimeout(char *sIpAddr, int iPort, int iTimeout)
{
	static int ErrNum = 0;
	int iSockFd = -1, on = 1;
	struct sockaddr_in sai;
	struct timeval timeo = {3, 0};
	socklen_t len = sizeof(timeo);

	if(iTimeout)
		timeo.tv_sec = iTimeout;

	memset(&sai, 0, sizeof(sai));
	sai.sin_family = AF_INET;
	sai.sin_port = htons(iPort);
	sai.sin_addr.s_addr = inet_addr(sIpAddr);
	
	iSockFd = socket(AF_INET, SOCK_STREAM, 0);
	if(iSockFd < 0) 
	{
		DBUG(  "[TCP_ConnectToServerTimeout]:socket create fail\n");
		return ERR_SOCKET;
	}
	
	setsockopt(iSockFd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);
	//setsockopt (iSockFd, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(on));

	if (connect(iSockFd, (struct sockaddr *)&sai, sizeof(sai)) < 0) 
	{
		if(ErrNum != errno)
		{
			DBUG(  "[TCP_ConnectToServerTimeout]:ConnectErr.%d:%s\n", errno, strerror(errno));
			ErrNum = errno;
		}

		close(iSockFd); //add by lk 20150514
		return ERR_CONNECT;
	}

	return iSockFd;
}

/** 
 * Brief description:
       Send message to server by Tcp 
 * Detail description:
 *     Send message in sendbuffer to server by socket nfd
 * @param[in]
   nfd
   pucSendBuf
   nSendLen
 * @param[out]  None
 * @retval  <=0 fail 
 * @retval  >0 success and the value will be the actul send bytes
 * @par  nfd:type is int
 *          
 * @par  pucSendBuf:point to message buffer
 *     
 * @par nSendLen:the sending bytes num
 *    
 */  
 #if 1
int TCP_SendMessage(int iSockFd, const PUCHAR pucSendBuf, int nSendLen)
{
    int nRealLen = -1;
	if( iSockFd < 0 )
		return 0;

    nRealLen = send(iSockFd, pucSendBuf, nSendLen, 0);
    if(nRealLen <= 0)
    {
        if((errno != EINTR) && (errno != EWOULDBLOCK))
            DBUG("TCP send: %s\n", strerror(errno));
    }
    DBUG("TCP send: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, \n%s", hex2str(pucSendBuf, nSendLen));

    return nRealLen;
}
#else
int TCP_SendMessage(int iSockFd, const PUCHAR pucSendBuf, int nSendLen)
{
	int iRtn,iPos=0;
	struct timeval tv;
	fd_set fdsWrite;
	
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	
	do{
		FD_ZERO(&fdsWrite);
		FD_SET(iSockFd, &fdsWrite);
		iRtn = select(iSockFd + 1, NULL, &fdsWrite, NULL, &tv);
		if(iRtn < 0 && errno != EINTR) 
			return ERR_SELECT;
		if(iRtn == 0) 
			return ERR_TIME_OUT;
		iRtn = send(iSockFd, pucSendBuf+iPos, nSendLen - iPos, 0);
		if(iRtn < 0) 
			return ERR_SEND;
		iPos+=iRtn;
	}while(iPos < nSendLen);

	return nSendLen;
}

#endif
#if 1
/*��socketȡָ�����ȵ����ݷ���sBuf��
iType=MSG_PEEK��MSG_WAITALL
iTimeOut��ʱʱ��,���Ϊ0,�����������ᳬʱ��*/
int TCP_RecvMessage(int iSockFd, unsigned char* sBuf, int iLen, int iType, int iTimeOut)
{
	int iRtn, iCurDataLen, iPos = 0;
	struct timeval tv;
	fd_set fdsRead;

	if( iSockFd < 0 )
		return ERR_RECV;
	
	tv.tv_sec = iTimeOut;
	tv.tv_usec = 0;
	
	do{
		FD_ZERO(&fdsRead);
		FD_SET(iSockFd, &fdsRead);
		if(iTimeOut == 0) 
			iRtn = select(iSockFd + 1, &fdsRead, NULL, NULL, NULL);
		else 
			iRtn = select(iSockFd + 1, &fdsRead, NULL, NULL, &tv);

		if(iRtn < 0) 
		{
			return ERR_SELECT;
		}
		else if(iRtn == 0) 
		{
			return ERR_TIME_OUT; 
		}

		if((iRtn = ioctl(iSockFd, FIONREAD, &iCurDataLen)) < 0) 
			return ERR_IOCTL;

		if(iLen == 0) 
			iLen = iCurDataLen;

		if(iCurDataLen > iLen - iPos) 
			iCurDataLen = iLen - iPos;

		if((iRtn = recv(iSockFd, sBuf + iPos, iCurDataLen, iType)) <= 0 && (iCurDataLen > 0 || iTimeOut == 0)) 
			return ERR_RECV;

		iPos += iRtn;
	}while(iPos < iLen);

	sBuf[iLen] = 0;

	DBUG("TCP send: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, \n%s", hex2str(sBuf, iLen));

	return iLen;
}

int TCP_RecvMessage_short(int iSockFd, unsigned char* sBuf, int iLen, int iType, int iTimeOut)
{
	int iRtn, iPos = 0;
	int cnt = 0;
	int iRecvLen = 0;
	if( iSockFd < 0 )
		return ERR_RECV;

	if(iLen == 0) 
		iRecvLen = 1024;
	else 
		iRecvLen = iLen;

	while(1)
	{
		iRtn = recv(iSockFd, sBuf, iRecvLen, MSG_DONTWAIT);
		if(iRtn > 0) 
			return iRtn;

		sleep(1);
		cnt ++ ;
		if(cnt > (iTimeOut)) 
			return ERR_TIME_OUT;
	}

	return iRtn;
}

#endif
int TCP_RecvMessage_ms(int iSockFd, unsigned char* sBuf, int iLen, int iType, int iTimeOut)
{
	int iRtn, iCurDataLen, iPos = 0;
	struct timeval tv;
	fd_set fdsRead;

	if( iSockFd < 0 )
		return ERR_RECV;
	
	tv.tv_sec = 0;
	tv.tv_usec = (iTimeOut * 1000);
	
	do{
		FD_ZERO(&fdsRead);
		FD_SET(iSockFd, &fdsRead);

		if(iTimeOut == 0) 
			iRtn = select(iSockFd + 1, &fdsRead, NULL, NULL, NULL);
		else 
			iRtn = select(iSockFd + 1, &fdsRead, NULL, NULL, &tv);

		if(iRtn < 0) 
			return ERR_SELECT;
		else if(iRtn == 0) 
			return ERR_TIME_OUT; 

		if((iRtn = ioctl(iSockFd, FIONREAD, &iCurDataLen)) < 0) 
			return ERR_IOCTL;

		if(iLen == 0) 
			iLen = iCurDataLen;

		if(iCurDataLen > iLen - iPos) 
			iCurDataLen = iLen - iPos;

		if((iRtn = recv(iSockFd, sBuf + iPos, iCurDataLen, iType)) <= 0 && (iCurDataLen > 0 || iTimeOut == 0)) 
			return ERR_RECV;

		iPos += iRtn;
	}while(iPos < iLen);

	sBuf[iLen] = 0;

	return iLen;
}

int SetSocketNonBlock(int iSock_fd)
{
	int iRet;
	int flags = fcntl(iSock_fd, F_GETFL, 0); 
	iRet = fcntl(iSock_fd, F_SETFL, flags | O_NONBLOCK);

	return iRet;
}

int SetSocketBlock(int iSock_fd)
{
	int iRet = fcntl(iSock_fd, F_SETFL, 0); 

	return iRet;
}
